/*******************************************************************************
 * Copyright (c) 2008 Sylvain Sicard.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Sylvain Sicard - initial API and implementation
 ******************************************************************************/
/***
 * Fractal RMI: a binder for remote method calls between Fractal components.
 * Copyright (C) 2003 France Telecom R&D
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Contact: Eric.Bruneton@rd.francetelecom.com
 *
 * Author: Eric Bruneton
 *
 * adapted from Jonathan:
 *   org.objectweb.jeremie.libs.presentation.StdMarshallerFactory
 *     (authors: B. Dumant, K. Milsted)
 */

package fr.jade.fraclite.orb.io;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.ref.Reference;

import org.objectweb.fractal.api.Interface;
import org.objectweb.fractal.api.type.InterfaceType;
import org.objectweb.naming.Binder;
import org.objectweb.naming.Name;
import org.objectweb.naming.NamingContext;

import fr.jade.fraclite.orb.names.TcpIpName;


/**
 * An {@link ObjectOutputStream} that replaces interface references with {@link
 * Ref} objects.
 */

public class RmiObjectOutputStream extends ObjectOutputStream {

  /**
   * The naming context used to export local interfaces, to make them
   * remotely accessible.
   */

  protected Binder namingContext;

  /**
   * Constructs a new {@link RmiObjectOutputStream}.
   *
   * @param os the underlying output stream.
   * @param binder the naming context to be used to export local interface
   *      references, to make them remotely accessible.
   * @throws IOException if the super constructor throws an exception.
   */

  public RmiObjectOutputStream (final OutputStream os, final Binder namingContext) throws IOException {
    super(os);
    enableReplaceObject(true);
    this.namingContext = namingContext;
  }

  /**
   * Replaces component interfaces with {@link RMIRef} objects. If the given
   * object is an {@link Interface}, two cases are possible. If the object is
   * also a {@link Name}, then it is replaced with a {@link RMIRef} object
   * containing an encoded form of the identifier held by the {@link Reference}.
   * If the object is not a {@link Reference}, then it is exported with {@link
   * #binder binder}, and replaced with a {@link RMIRef} object containing an
   * encoded form of the {@link Name} returned by {@link NamingContext#export export}.
   *
   * @param obj an object.
   * @return a {@link RMIRef} object if <tt>obj</tt> is a component interface,
   *      or <tt>obj</tt> otherwise.
   * @throws IOException if a component interface cannot be replaced with a
   *      {@link RMIRef} object.
   */

  protected Object replaceObject (final Object obj) throws IOException {
    if (obj instanceof Interface) {
      try {
        Ref ref = new Ref();
        if (obj instanceof Name) {
          ref.name = ((Name)obj).encode();
        } else {
          ref.name = namingContext.export(obj, null).encode();
        }
        //System.out.println("[RmiObjectOutputStream] "+new String(ref.name));
        return ref;
      } catch (Exception e) {
        e.printStackTrace();
        throw new IOException("Cannot export object: " + e);
      }
    }
    return obj;
  }

}
